"""
AI模块 - 增强版
包含智能叫地主策略和出牌策略
"""

from collections import defaultdict
import random
from itertools import combinations
from rules import RuleEngine
from card import Card  # 添加这行导入

class DoudizhuAI:
    def __init__(self, player_id, hand):
        self.player_id = player_id
        self.hand = sorted(hand, key=lambda x: x.value)
        self.known_cards = set(hand)  # 已知牌池（用于记牌）
        self.role = "farmer"  # 初始化身份，后续会更新

    def update_knowledge(self, played_cards):
        """更新已知牌池"""
        self.known_cards.update(played_cards)

    def make_bid(self):
        """
        增强叫地主策略
        返回: True/False
        """
        # 手牌强度评估
        strength = 0
        
        # 基础分计算
        counter = self._count_ranks()
        strength += self._base_score(counter)
        
        # 特殊组合加分
        strength += self._bomb_bonus(counter)         # 炸弹加成
        strength += self._joker_bonus()               # 王炸加成
        strength += self._sequence_bonus(counter)     # 顺子加成
        strength += self._chain_pair_bonus(counter)   # 连对加成
        
        # 调整因子
        strength *= self._adjustment_factor(counter)
        
        return strength > 28  # 经验阈值

    def select_action(self, last_play=None):
        """
        增强出牌策略
        返回: 选择的卡牌列表
        """
        legal_plays = self._get_legal_plays(last_play)
        if not legal_plays:
            return []
        
        # 策略选择优先级
        if not last_play:  # 主动出牌
            return self._active_play_strategy(legal_plays)
        else:               # 被动跟牌
            return self._reactive_play_strategy(legal_plays, last_play)

    # ---------- 策略核心方法 ----------
    def _active_play_strategy(self, legal_plays):
        """主动出牌策略"""
        # 优先出最小且不影响关键牌型的组合
        scored_plays = []
        for play in legal_plays:
            score = 0
            play_type = RuleEngine.validate_play(play)[1]
            
            # 基础分
            score += len(play) * 2  # 长牌优先
            
            # 类型调整
            if play_type[0] in ['sequence', 'chain_pair']:
                score += 5  # 顺子/连对优先
            elif play_type[0] == 'single':
                score -= 3  # 单牌延后
            
            # 保护关键牌
            if self._is_key_card(play):
                score -= 15
            
            scored_plays.append( (score, play) )
        
        # 选择最高分且最小的合法出牌
        scored_plays.sort(reverse=True, key=lambda x: (x[0], -x[1][0].value))
        return scored_plays[0][1]

    def _reactive_play_strategy(self, legal_plays, last_play):
        """被动跟牌策略"""
        target_type = last_play[1][0]
        target_value = last_play[1][1]
        
        # 生成候选列表
        candidates = []
        for play in legal_plays:
            play_type = RuleEngine.validate_play(play)[1]
            if play_type[0] == target_type and play_type[2] == last_play[1][2]:
                candidates.append(play)
        
        # 寻找最小压制牌
        if candidates:
            return min(candidates, key=lambda x: x[0].value)
        
        # 使用炸弹策略
        if self._should_use_bomb(last_play):
            bomb_plays = [p for p in legal_plays if RuleEngine.validate_play(p)[1][0] == 'bomb']
            if bomb_plays:
                return bomb_plays[0]
        
        return []  # 不出

    # ---------- 辅助方法 ----------
    def _count_ranks(self):
        """统计各点数的数量"""
        counter = defaultdict(int)
        for card in self.hand:
            counter[card.rank] += 1
        return counter

    def _base_score(self, counter):
        """基础分计算"""
        score = 0
        # 大牌分（2、A、K、Q、J）
        score += sum(4 * counter[r] for r in ['2', 'A'])
        score += sum(2 * counter[r] for r in ['K', 'Q', 'J'])
        # 三张/四张加成
        score += sum(10 * count for count in counter.values() if count == 3)
        score += sum(15 * count for count in counter.values() if count == 4)
        return score

    def _bomb_bonus(self, counter):
        """炸弹加成"""
        bomb_count = sum(1 for cnt in counter.values() if cnt >= 4)
        return bomb_count * 20

    def _joker_bonus(self):
        """王炸加成"""
        has_jokers = any(c.value >= 14 for c in self.hand)
        return 25 if has_jokers else 0

    # def _sequence_bonus(self, counter):
    #     """顺子加成"""
    #     sorted_ranks = sorted([Card.VALUES[r] for r in counter.keys()])
    #     max_streak = self._longest_consecutive(sorted_ranks)
    #     return max(0, (max_streak - 4) * 5)  # 5张以上开始加分

    # def _chain_pair_bonus(self, counter):
    #     """连对加成"""
    #     pairs = [r for r, cnt in counter.items() if cnt >= 2]
    #     sorted_pairs = sorted([Card.VALUES[r] for r in pairs])
    #     max_streak = self._longest_consecutive(sorted_pairs)
    #     return max(0, (max_streak - 2) * 4)  # 3连对以上加分


    def _sequence_bonus(self, counter):
        """顺子加成（修复版）"""
        sorted_ranks = sorted([Card.VALUES[r] for r in counter.keys() if r in Card.VALUES])
        max_streak = self._longest_consecutive(sorted_ranks)
        return max(0, (max_streak - 4) * 5)

    def _chain_pair_bonus(self, counter):
        """连对加成（修复版）"""
        pairs = [r for r, cnt in counter.items() if cnt >= 2 and r in Card.VALUES]
        sorted_pairs = sorted([Card.VALUES[r] for r in pairs])
        max_streak = self._longest_consecutive(sorted_pairs)
        return max(0, (max_streak - 2) * 4)
    


    def _adjustment_factor(self, counter):
        """平衡因子"""
        single_count = sum(1 for cnt in counter.values() if cnt == 1)
        # 单牌过多降低评分
        return max(0.5, 1 - single_count * 0.1)

    def _longest_consecutive(self, nums):
        """计算最长连续序列"""
        if not nums:
            return 0
        nums = sorted(set(nums))
        max_len = 1
        current = 1
        for i in range(1, len(nums)):
            if nums[i] == nums[i-1] + 1:
                current += 1
                max_len = max(max_len, current)
            else:
                current = 1
        return max_len

    def _get_legal_plays(self, last_play):
        """获取所有合法出牌"""
        legal_plays = []
        last_type = last_play[1] if last_play else None
        
        for r in range(1, len(self.hand)+1):
            for combo in combinations(self.hand, r):
                is_valid, play_type = RuleEngine.validate_play(combo, last_play)
                if is_valid:
                    legal_plays.append(list(combo))
                    
        return legal_plays

    def _is_key_card(self, play):
        """判断是否包含关键牌"""
        key_ranks = {'2', 'A', 'K', 'Q', 'J', 'BJ', 'RJ'}
        return any(c.rank in key_ranks or c.value >= 14 for c in play)

    def _should_use_bomb(self, last_play):
        """判断是否使用炸弹（修复版）"""
        # 查找地主玩家
        landlord = next((p for p in self.players if p.role == 'landlord'), None)
        if not landlord:
            return False
        
        # 地主只剩1-2张牌时必炸
        if self.role == 'farmer' and len(landlord.hand) <= 2:
            return True
        # 关键牌被压制时使用
        if last_play[1][0] == 'bomb' and len(self.hand) < 10:
            return True
        return False